package evaluator

import (
	"fmt"
	"monkey/token"
	"monkey/ast"
	"monkey/object"
)

func quote(node ast.Node,env *object.Environment) object.Object{
	node = evalUnquoteCalls(node,env)
	return &object.Quote{Node: node}
}

func isUnquoteCall(node ast.Node) bool{
	unquotedCall,ok := node.(*ast.CallExpression)
	if !ok{
		return false
	}
	return unquotedCall.Function.TokenLiteral() == "unquote"
}

func parseUnquoteFunc(node ast.Node,env *object.Environment)ast.Node{
	if isUnquoteCall(node){
		call,ok := node.(*ast.CallExpression)
		if !ok{
			return node
		}
		if len(call.Arguments) != 1{
			return node
		}
		return node
	}
	return node
}
func evalUnquoteCalls(quoted ast.Node,env *object.Environment) ast.Node{
	return ast.Modify(quoted,func(node ast.Node)ast.Node{
		if isUnquoteCall(node){
			call,ok := node.(*ast.CallExpression)
			
			if !ok{
				return node
			}
			if len(call.Arguments) != 1{
				return node
			}
			unquoted := Eval(call.Arguments[0],env)
			return convertObjectToASTNode(unquoted)
		}
		return node
	})
}
//convertObjectToASTNode 因为映射函数是ast.Node->ast.Node的类型映射，而
//Eval返回的是object.Object类型的对象，必须实现类型转化
func convertObjectToASTNode(obj object.Object) ast.Node{
	switch obj := obj.(type){
	case *object.Integer:
		t := token.Token{
			Type:token.INT,
			Literal: fmt.Sprintf("%d",obj.Value),
		}
		return &ast.IntegerLiteral{Token:t,Value:obj.Value}
		//TODO:忽略其他可能的错误
	case *object.Boolean:
		var t token.Token
		if obj.Value{
			t = token.Token{Type:token.TRUE,Literal: "true"}
		}else{
			t = token.Token{Type:token.FALSE,Literal: "false"}
		}
		return &ast.Boolean{Token:t,Value:obj.Value}
	case *object.Quote:
		return obj.Node
	default:
		return nil
	}
}